昨天將資料在使用者端加鹽過後,今天要將這筆資料做驗證,但是要如何驗證是一個讓我想破頭的事,由於 keccak256
的 hash 方式是一個非對稱式加密,我們在系統中要如何再取得用戶資訊並同時進行驗證,這一點讓我想了很久。
上次我們使用了 component-qrscanner
這個套件來得到 QRCode 的資訊,現在我們也會利用這個套件來完成驗證所需要做到的事情。
const fn = (e) => {
if(e.text) {
const QrData = e.text;
}
else {
alert('error: ' + e.error);
}
}
const scanner = new CreateQRScanner(fn);
scanner.start()
return (
<div></div>
);
上次使用的程式碼長這樣,其實我之前一直搞不懂在 react 中的 event 到底代表什麼,因此今日我也想趁機來搞懂他的意思。
原生的 js 中會使用「addEventListener」負責「偵測發生了什麼事」,例如在我的(學校)作業中有遇到要將自己刻的一個 Google Meet 網頁上的人物踢出,可以看下圖:
在這段區塊中的我使用很多層 tag 來包起來,最後我使用下面這段程式來讓電腦偵測到我點擊了 cancel
的按鍵。
let cancelBtns = document.querySelectorAll('#cancelBtn');
Array.from(cancelBtns).forEach(function(cancelBtn){
cancelBtn.addEventListener('click', function(e) {
const audBox = e.target.parentElement.parentElement.parentElement;
audBox.parentNode.removeChild(audBox);
accountNum -= 1;
if (accountNum === 1) {
mainChar.style.width = '100%';
audiences.style.width = '0%';
}
});
});
簡單說就是我們利用 document.querySelectorAll(id)
來抓到全部具有 #cancelBtn
這個 id 的tag (回傳一個 list),再使用 Array.from().forEach()
來遍歷整個 list,這時當我們按下按鈕時就會被 cancelBtn.addEventListener(‘click’, function)
監測到並開始執行其中的函式。
在 React.js 中使用了 W3C 在 2016 改動的 UI Events,這個 UI Event 便是用來處理 Client 端使用滑鼠或鍵盤時與前端的互動媒介。
event 在 DOM 中的傳遞流程
通常我們使用的都是 event listener,其主要是提供一個 EventListener 的介面,並會提供一個 callback function: handleEvent()
。而 Eventhandler()
會觸發 event.target
這個 Object,前段便可以使用這個 Object 執行收到 event 後的 statement。
在 React 中可以直接呼叫 event
,而不用像原生 JS 使用 addEventListener()
,方便了很多。
onClick = e => {...}
了解了 event 在做什麼後,回過頭看那段程式應該是可以輕鬆了解。
const fn = (e) => {}
首先函式一開始傳入一個 event,可以用這個函式來得知使用者的任何操作,
在此是指 webCam 的掃描動作。
當 event 接收到任何資料的時候會回傳一個 object:
format: 11
numBits: 528
rawBytes: Uint8Array(66) [64, 83, 7, 134, 99, 54, 97, 1, 189, 41, 209, 5, 88, 153, 142, 25, 24, 204, 217, 24, 77, 204, 13, 153, 77, 205, 88, 204, 204, 140, 24, 204, 88, 196, 7, 213, 9, 217, 64, 246, 22, 22, 70, 35, 99, 70, 51, 150, 22, 54, 35, 86, 67, 118, 65, 2, 69, 93, 50, 103, 64, 54, 67, 51, 0, 236, buffer: ArrayBuffer(66), byteLength: 66, byteOffset: 0, length: 66, Symbol(Symbol.toStringTag): 'Uint8Array']
resultMetadata: Map(2) {2 => Array(4), 3 => 'H'}
resultPoints: (4) [e, e, e, e]
text: "0xf3f978628bf8dc3da706e75c320c1c8521579aadb64c9acb5d7d085844615d30"
timestamp: 1665377085645
[[Prototype]]: Object
我們需要的則是裡面的 e.text
,因此用一個變數qrData
將他抓起來。
這邊用 wikipedia 的 QRCode,測試成功!(好害羞)
由於我們在 Client 端已經使用 keccak256()
進行雜湊了,因此我們能做的驗證方式就是一樣 fetch Opensea 上的資料,然後將 ticket Owner 的 address 一個個做同樣的 hash,將其轉換成一個 array,若是有 hash 在裡面表示「這個使用者確實是使用我們的前端加密轉換成 QRCode 的!」
這邊的做法可能會在使用者數量很大的時候出現問題,感覺應該可以使用後端先儲存,並在收到 QRCode 資料的時候去後端驗證。但是因為我目前無法處理後端的開發,未來可能會改善。
那就事不宜遲直接來實作吧!
首先使用 useEffect()
來偵測是否有 fetch 到資料,有的話再確認是否已將 ownership 處理過並丟到 hashedOwnerList
中。
useEffect(() => {
if (nftData !== null) {
if (hashedOwnerList.length !== nftData.top_ownerships.length){
// first generate ownership array
const topOwnerships = nftData.top_ownerships;
let tmpOwnerList = [];
for (let i = 0; i < topOwnerships.length; i++) {
tmpOwnerList.push(hash(topOwnerships[i].owner.address));
}
console.log(tmpOwnerList);
// to update in a useState;
for (let i = 0; i < tmpOwnerList.length; i++) {
setHashedOwnerList( previousList => {
return [
...previousList,
tmpOwnerList[i]
]
});
}
}
}
}, [qrData, nftData, hashedOwnerList]);
使用的函式 buf2hex()
在昨日已提過了,可見昨日文章,而 hash()
則是將 message 與地址進行 encodePacked()
再執行 keccak256()
並轉成 hex
的形式。
const hash = (addr) => {
const addedMessage = "token3_audience_tickets";
const encodePackedMessage = Web3.utils.encodePacked( addedMessage, addr);
const hashedMessage = buf2hex(keccak256(encodePackedMessage));
return hashedMessage;
}
最後設置當 scanner 掃瞄到資料便開始比對資料是否有對應者,有的話就 alert('Verify Success! You can get in')
,沒有的話則判斷其持有假的 NFT QRCode。
將 QRCode 轉換成資料真的花費了我好多時間,中間還一度要改用其他套件,但用來用去似乎還是這個最簡單明瞭。另外也搞懂了一些關於 event 的知識,希望未來在處理 event 時可以更順手!
若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!
歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4